﻿using Microsoft.VisualStudio.OLE.Interop;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SolidEdgeDraft;

namespace DemoTG
{
    /// <summary>
    /// 所有自定义数据如使用二进制序列化时，实现此接口
    /// </summary>
    public interface IBinaryData
    {
        bool WriteToStream(MemoryStream memStream);
        bool ReadFromStream(MemoryStream memStream);
    }



    public class TGPropReadWrite
    {
        private string _rootStgName;  // 仓库独有的名字
        private string _streamName;   // 流名


        public TGPropReadWrite(string rootStgName, string streamName)
        {
            _rootStgName = rootStgName;
            _streamName = streamName;
        }


        /// <summary>
        /// 将数据写入到文档中
        /// </summary>
        /// <param name="doc"> 文档</param>
        /// <param name="info"> 数据(以二进制方式序列化)</param>
        /// <returns></returns>
        public bool WriteDataToDoc(SolidEdgeFramework.SolidEdgeDocument doc, IBinaryData info)
        {
            if (null == doc || null == info)
                return false;
            IStorage pRootStg = null;
            IStorage pRootSubStg = null;
            try
            {
                // 尝试读写存储区域，如未打开，则创建

                try
                {
                    pRootStg = doc.AddInsStorage[_rootStgName, (int)(STGM.DIRECT | STGM.READWRITE | STGM.SHARE_EXCLUSIVE)] as IStorage;
                }
                catch (Exception ex)
                {
                    pRootStg = doc.AddInsStorage[_rootStgName, (int)(STGM.DIRECT | STGM.READWRITE | STGM.CREATE | STGM.SHARE_EXCLUSIVE)] as IStorage;
                }

                try
                {
                    // 尝试在其下打开一个同名子存储
                    IntPtr pUnsed = IntPtr.Zero;
                    pRootStg.OpenStorage(_rootStgName, null, (int)(STGM.DIRECT | STGM.READWRITE | STGM.SHARE_EXCLUSIVE), pUnsed, 0, out pRootSubStg);
                }
                catch (Exception ex)
                {
                    // 还未有，则创建此同名子存储
                    IntPtr pUnsed = IntPtr.Zero;
                    pRootStg.CreateStorage(_rootStgName, (int)(STGM.DIRECT | STGM.READWRITE | STGM.CREATE | STGM.SHARE_EXCLUSIVE), 0, 0, out pRootSubStg);
                }

                // 尝试读写流，如未打开，则创建
                IntPtr pReserve = IntPtr.Zero;
                pRootSubStg.CreateStream(_streamName, (int)(STGM.READWRITE | STGM.CREATE | STGM.SHARE_EXCLUSIVE), 0, 0, out IStream pStream);


                // 写入数据
                MemoryStream memStream = new MemoryStream();
                if (!info.WriteToStream(memStream))
                {
                    memStream.Close();
                    return false;
                }

                int streamSize = (int)memStream.Length;
                byte[] byteData = new byte[streamSize];
                memStream.Seek(0, SeekOrigin.Begin);
                memStream.Read(byteData, 0, streamSize);

                pStream.Write(byteData, (uint)streamSize, out uint pcbWritten);
                memStream.Close();

                // 提交并保存
                pStream.Commit((uint)(STGC.STGC_DEFAULT | STGC.STGC_OVERWRITE));
                pRootStg.Commit((uint)(STGC.STGC_DEFAULT | STGC.STGC_OVERWRITE));
                IPersistStorage pPersistStg = doc as IPersistStorage;
                pPersistStg.Save(pRootStg, 0);

                System.Runtime.InteropServices.Marshal.ReleaseComObject(pStream);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(pRootSubStg);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(pRootStg);
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (pRootSubStg != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pRootSubStg);
                }

                if (pRootStg != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pRootStg);
                }
            }
        }


        public bool ReadCurveDataFromDoc<T>(ref IStorage pRootStg, ref IStorage pRootSubStg, SolidEdgeFramework.SolidEdgeDocument doc, ref List<T> infoList) where T : IBinaryData, new()
        {

            try
            {
                // 尝试读写存储区域，如未打开，则创建
                if (null == pRootStg)
                {
                    pRootStg = doc.AddInsStorage[_rootStgName, (int)(STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE)] as IStorage;
                }

                // 读其同名子存储
                IntPtr pUnsed = IntPtr.Zero;
                if (null == pRootSubStg)
                {
                    pRootStg.OpenStorage(_rootStgName, null, (int)(STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE), pUnsed, 0, out pRootSubStg);
                }

                // 枚举子存储下所有流
                uint reserved1 = 0, reserved3 = 0;
                IntPtr pReserved2 = IntPtr.Zero;
                pRootSubStg.EnumElements(reserved1, pReserved2, reserved3, out IEnumSTATSTG pEnum);

                STATSTG[] staastg = new STATSTG[1];
                while (pEnum.Next(1, staastg, out uint pceltFetched) == 0)
                {
                    string steamName = staastg[0].pwcsName;
                    if (!steamName.StartsWith("Curve"))
                        continue;

                    // 尝试打开流，如未打开，则创建
                    IntPtr pReserve = IntPtr.Zero;
                    pRootSubStg.OpenStream(steamName, pReserve, (int)(STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE), 0, out IStream pStream);

                    // 写入数据
                    STATSTG[] stat = new STATSTG[1];
                    pStream.Stat(stat, 0);
                    ulong cbSize = stat[0].cbSize.QuadPart;
                    byte[] byteData = new byte[cbSize];
                    pStream.Read(byteData, (uint)cbSize, out uint pcbRead);

                    MemoryStream memStream = new MemoryStream(byteData);
                    T data = new T();
                    IBinaryData info = data as IBinaryData;

                    if (!info.ReadFromStream(memStream))
                    {
                        memStream.Close();
                        return false;
                    }
                    infoList.Add(data);

                    memStream.Close();

                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pStream);
                }

                return true;
            }
            catch (Exception ex)
            {

                return false;
            } finally
            {
                if (pRootSubStg != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pRootSubStg);
                    pRootSubStg = null;
                }

                if (pRootStg != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pRootStg);
                    pRootStg = null;
                }
            }


        }

        public bool ReadDataFromDoc(ref IStorage pRootStg, ref IStorage pRootSubStg, SolidEdgeFramework.SolidEdgeDocument doc, ref IBinaryData info)
        {
            if (null == doc || null == info)
                return false;

            try
            {
                // 尝试读写存储区域，如未打开，则创建
                if (null == pRootStg)
                {
                    pRootStg = doc.AddInsStorage[_rootStgName, (int)(STGM.DIRECT | STGM.READ)] as IStorage;
                }

                // 读其同名子存储
                IntPtr pUnsed = IntPtr.Zero;
                if (null == pRootSubStg)
                {
                    pRootStg.OpenStorage(_rootStgName, null, (int)(STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE), pUnsed, 0, out pRootSubStg);
                }


                // 尝试读写流，如未打开，则创建
                IntPtr pReserve = IntPtr.Zero;
                pRootSubStg.OpenStream(_streamName, pReserve, (int)(STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE), 0, out IStream pStream);

                // 写入数据
                STATSTG[] stat = new STATSTG[1];
                pStream.Stat(stat, 0);
                ulong cbSize = stat[0].cbSize.QuadPart;
                byte[] byteData = new byte[cbSize];
                pStream.Read(byteData, (uint)cbSize, out uint pcbRead);

                MemoryStream memStream = new MemoryStream(byteData);
                if (!info.ReadFromStream(memStream))
                {
                    memStream.Close();
                    return false;
                }

                memStream.Close();
                if (pStream != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pStream);
                    pStream = null;
                }
                return true;
            }
            catch (Exception ex)
            {

                return false;
            }
            finally
            {
                if (pRootSubStg != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pRootSubStg);
                    pRootSubStg = null;
                }

                if (pRootStg != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pRootStg);
                    pRootStg = null;
                }
            }
        }

        public bool ReadDataFromDoc(out string data, ref IStorage pRootStg, SolidEdgeFramework.SolidEdgeDocument doc)
        { 

                data = "";
            if (null == doc )
                return false;

            try
            {
                // 尝试读写存储区域，如未打开，则创建
                if (null == pRootStg)
                {
                    pRootStg = doc.AddInsStorage[_rootStgName, (int)(STGM.DIRECT | STGM.READ)] as IStorage;
                }

                // 读其同名子存储
                IntPtr pUnsed = IntPtr.Zero;

                // 尝试读写流，如未打开，则创建
                IntPtr pReserve = IntPtr.Zero;
                pRootStg.OpenStream(_streamName, pReserve, (int)(STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE), 0, out IStream pStream);

                // 读取数据
                // 首先读取数据长度
                byte[] cbSizeData = new byte[sizeof(UInt64)];
                pStream.Read(cbSizeData, sizeof(UInt64), out uint cbRead);
                UInt64 cbSize = BitConverter.ToUInt64(cbSizeData, 0);
               
                byte[] byteData = new byte[cbSize];
                pStream.Read(byteData, (uint)cbSize, out uint pcbRead);
                data = System.Text.Encoding.UTF8.GetString(byteData);

                if (pStream != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pStream);
                    pStream = null;
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
            finally
            {
                if (pRootStg != null)
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pRootStg);
                    pRootStg = null;
                }
            }
        }

    }

    /// <summary>
    /// 单层描述
    /// </summary>
    public class LaminateDesc:IBinaryData
    {
        public string LayerName=""; //名称
        public int LayerAngle = 0; //角度
        public double LayerThickness = 0; // 厚度

        public LaminateDesc( string name, int angle, double thickness)
        {
            LayerName = name;
            LayerAngle = angle;
            LayerThickness = thickness;
        }

        bool IBinaryData.ReadFromStream(MemoryStream memStream)
        {
            LayerName = NDSNexInterface.ReadStringFromStream(memStream);
            LayerAngle = NDSNexInterface.ReadIntFromStream(memStream);
            LayerThickness = NDSNexInterface.ReadDoubleFromStream(memStream);
            return true;
        }

        bool IBinaryData.WriteToStream(MemoryStream memStream)
        {
            NDSNexInterface.WriteStringToStream(memStream, LayerName);
            NDSNexInterface.WriteIntToStream(memStream, LayerAngle);
            NDSNexInterface.WriteDoubleToStream(memStream, LayerThickness);
            return true;
        }
    }

    public class SurfaceInfo : IBinaryData
    {
        public int SurfaceID = 0; // 曲面ID
        public int Num = 0;  //数量
        public string MaterialName = ""; //材质名称
        bool IBinaryData.ReadFromStream(MemoryStream memStream)
        {
            SurfaceID = NDSNexInterface.ReadIntFromStream(memStream);
            Num = NDSNexInterface.ReadIntFromStream(memStream);
            MaterialName = NDSNexInterface.ReadStringFromStream(memStream);
            return true;
        }

        bool IBinaryData.WriteToStream(MemoryStream memStream)
        {
            NDSNexInterface.WriteIntToStream(memStream, SurfaceID);
            NDSNexInterface.WriteIntToStream(memStream, Num);
            NDSNexInterface.WriteStringToStream(memStream, MaterialName);
            return true;
        }
    }
        /// <summary>
        ///   铺层描述
        /// </summary>
        public class PlyModel: IBinaryData
    {
        public string ModelName = "MBD001";  //模型名称
        
        public Dictionary<string, LaminateDesc> LayerList;  //铺层中各单层描述
        public PlyModel(string modelName)
        {
            ModelName = modelName;
            LayerList = new Dictionary<string, LaminateDesc>();
        }

        /// <summary>
        /// 在铺层中创建一层
        /// </summary>
        /// <param name="lyDesc"></param>
        public void InsertOrAssign(in LaminateDesc lyDesc)
        {
            LayerList[lyDesc.LayerName] = lyDesc;
        }

        bool IBinaryData.ReadFromStream(MemoryStream memStream)
        {
            ModelName = NDSNexInterface.ReadStringFromStream(memStream);

            int lyCnt = NDSNexInterface.ReadIntFromStream(memStream);
            LayerList.Clear();
            for(int i =0;i < lyCnt; i++)
            {
                LaminateDesc pLayer = new LaminateDesc("",0,0) ;
                IBinaryData info = pLayer as IBinaryData;
                info.ReadFromStream(memStream);
                InsertOrAssign(pLayer);               
            }
            return true;
        }

        bool IBinaryData.WriteToStream(MemoryStream memStream)
        {
            try
            {
                NDSNexInterface.WriteStringToStream(memStream, ModelName);
                int lyCnt = LayerList.Count;
                NDSNexInterface.WriteIntToStream(memStream, lyCnt);
                foreach (KeyValuePair<string, LaminateDesc> kv in LayerList)
                {
                    IBinaryData info = kv.Value as IBinaryData;
                    info.WriteToStream(memStream);
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }
    }
}
